package com.ssy.lingxi.member.merchant.serviceimpl.openapi;

import com.ssy.lingxi.common.constant.basic.EnableDisableStatus;
import com.ssy.lingxi.common.constant.member.MemberConfigTagEnum;
import com.ssy.lingxi.common.constant.member.MemberLevelTypeEnum;
import com.ssy.lingxi.common.constant.member.MemberStatusEnum;
import com.ssy.lingxi.common.response.ResponseCode;
import com.ssy.lingxi.common.response.Wrapper;
import com.ssy.lingxi.common.utils.PasswordUtil;
import com.ssy.lingxi.member.merchant.api.constant.MemberRelationTypeEnum;
import com.ssy.lingxi.member.merchant.api.model.constant.MemberProcessTypeEnum;
import com.ssy.lingxi.member.merchant.api.model.openapi.request.MemberOpenApiCreateVO;
import com.ssy.lingxi.member.merchant.api.model.openapi.response.MemberOpenApiCreateResultVO;
import com.ssy.lingxi.member.merchant.config.ServiceConfig;
import com.ssy.lingxi.member.merchant.entity.*;
import com.ssy.lingxi.member.merchant.model.bo.DetailCheckBO;
import com.ssy.lingxi.member.merchant.model.constant.*;
import com.ssy.lingxi.member.merchant.repository.*;
import com.ssy.lingxi.member.merchant.service.base.IBaseMemberHistoryService;
import com.ssy.lingxi.member.merchant.service.base.IBaseMemberLevelConfigService;
import com.ssy.lingxi.member.merchant.service.base.IBaseMemberRegisterDetailService;
import com.ssy.lingxi.member.merchant.service.feign.IPayFeignService;
import com.ssy.lingxi.member.merchant.service.openapi.IMemberOpenApiCreationService;
import com.ssy.lingxi.member.merchant.utils.SecurityStringUtils;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.*;

/**
 * OpenApi - 会员创建相关接口实现类
 * @author 万宁
 * @version 2.0.0
 * @date 2021-10-15
 */
@Service
public class MemberOpenApiCreationServiceImpl implements IMemberOpenApiCreationService {
    @Resource
    private MemberRepository memberRepository;

    @Resource
    private RoleRepository roleRepository;

    @Resource
    private MemberRelationRepository relationRepository;

    @Resource
    private MemberRoleRepository memberRoleRepository;

    @Resource
    private MemberUserRepository memberUserRepository;

    @Resource
    private MemberRegisterDetailRepository memberRegisterDetailRepository;

    @Resource
    private IBaseMemberRegisterDetailService baseMemberRegisterDetailService;

    @Resource
    private IBaseMemberLevelConfigService baseMemberLevelConfigService;

    @Resource
    private IBaseMemberHistoryService baseMemberHistoryService;

    @Resource
    private IPayFeignService payFeignService;

    /**
     * 创建会员
     *
     * @param createVO 接口参数
     * @return 创建结果
     */
    @Override
    public Wrapper<MemberOpenApiCreateResultVO> createMember(MemberOpenApiCreateVO createVO) {
        // **********************************
        //Step 1: 检查角色、注册资料、“平台会员”、“平台角色” 等固定配置（根据项目实际配置修改）
        // **********************************
        //"平台后台“会员、角色
        MemberDO adminMember = memberRepository.findFirstByAccount("admin");
        RoleDO adminRole = roleRepository.findFirstByRelType(MemberRelationTypeEnum.PLATFORM.getCode());

        //会员要注册的角色
        RoleDO roleDO = roleRepository.findById(1000L).orElse(null);
        if(roleDO == null) {
            return Wrapper.fail(ResponseCode.MC_MS_ROLE_DOES_NOT_EXIST);
        }


        //**********************************
        // 会员表 MemberDO 说明：
        //      1) “平台后台”作为根会员，所有会员都是“平台后台”的下级会员，其账号为“admin”
        //      2) account、phone、name、email 这四个字段，全局唯一
        //**********************************

        //**************************
        // 创建会员、会员角色、平台会员关系
        //**************************
        MemberDO memberDO = new MemberDO();
        //注册时间
        memberDO.setRegisterTime(LocalDateTime.now());
        //设置会员名称（即公司名称）
        memberDO.setName(createVO.getName());
        //设置邮箱（邮箱如果非空，全局唯一）
        memberDO.setEmail("");
        //设置支付密码为空
        memberDO.setPayPassword("");
        //注册来源，如果有其他来源，在枚举中添加值
        memberDO.setSource(MemberRegisterSourceEnum.FROM_ENTERPRISE_WEB_SHOP.getCode());
        //会员头像
        memberDO.setLogo("");

        //密码（默认使用MD5加密）
        memberDO.setPassword(PasswordUtil.instance().tryMd5PlainString(createVO.getPassword()));
        //国家代码设置为“+86”,即中国
        memberDO.setCountryCode("+86");
        //或：
        //memberDO.setCountryCode(CountryCodeEnum.China.getCode());

        //手机号即账号
        memberDO.setPhone(createVO.getPhone());
        memberDO.setAccount(createVO.getPhone());
        //设置角色和权限
        Set<RoleDO> roleDoSet = new HashSet<>();
        roleDoSet.add(roleDO);
        memberDO.setRoles(roleDoSet);

        MemberAuthDO memberAuth = new MemberAuthDO();
        memberAuth.setAuth(roleDO.getRoleAuth().getAuth());
        memberAuth.setMember(memberDO);
        memberDO.setMemberAuth(memberAuth);


        //由于关联关系是CascadeType.DETACH，所以要先保存一下注册资料列表，再保存MemberDO
        Wrapper<List<MemberRegisterDetailDO>> memberRegisterDetailResult = checkMemberRegisterDetail(new HashMap<>(), roleDO);
        if(memberRegisterDetailResult.getCode() != ResponseCode.SUCCESS.getCode()) {
            return Wrapper.fail(memberRegisterDetailResult.getCode(), memberRegisterDetailResult.getMessage());
        }

        List<MemberRegisterDetailDO> memberRegisterDetails = memberRegisterDetailResult.getData();
        memberRegisterDetailRepository.saveAll(memberRegisterDetails);

        memberDO.setRegisterDetails(new HashSet<>(memberRegisterDetails));
        memberRepository.saveAndFlush(memberDO);

        //设置注册资料与会员的关联
        memberRegisterDetails.forEach(memberRegisterDetailDO -> memberRegisterDetailDO.setMember(memberDO));
        memberRegisterDetailRepository.saveAll(memberRegisterDetails);

        //第二步骤：创建上下级关系，以及审核状态
        MemberRelationDO relationDO = new MemberRelationDO();
        relationDO.setCreateTime(LocalDateTime.now());
        relationDO.setMemberId(adminMember.getId());
        relationDO.setMember(adminMember);
        relationDO.setRoleId(adminRole.getId());
        relationDO.setRole(adminRole);
        relationDO.setSubMemberId(memberDO.getId());
        relationDO.setSubMember(memberDO);
        //注意这里：会员类型是要根据角色判断的
        relationDO.setSubMemberTypeEnum(roleDO.getMemberType().getTypeEnum());
        //上级为平台，所以等级类型为平台会员
        relationDO.setSubMemberLevelTypeEnum(MemberLevelTypeEnum.PLATFORM.getCode());
        relationDO.setSubRoleId(roleDO.getId());
        relationDO.setSubRole(roleDO);
        relationDO.setSubRoleName(roleDO.getRoleName());
        //这个字段表示会员关系是“平台会员”，还是其他会员关系
        relationDO.setRelType(MemberRelationTypeEnum.PLATFORM.getCode());
        //会员关系的注册来源（由于原型设计的会员注册来源，与实际应用中有冲突，所以一般都用这个字段）
        relationDO.setRelSource(MemberRelationSourceEnum.WEB_REGISTER.getCode());

        //***************************
        //审核状态、内部状态、外部状态：直接设置为“审核通过”
        //****************************
        relationDO.setVerified(MemberValidateStatusEnum.VERIFY_PASSED.getCode());
        relationDO.setInnerStatus(PlatformInnerStatusEnum.VERIFY_PASSED.getCode());
        relationDO.setOuterStatus(MemberOuterStatusEnum.PLATFORM_VERIFY_PASSED.getCode());
        //入库时间（审核通过时间）
        relationDO.setDepositTime(LocalDateTime.now());

        //这个是“审核不通过”的原因，设置为空字符串
        relationDO.setValidateMsg("");

        //会员状态（这里如果不设置为“正常”，则无法登录
        relationDO.setStatus(MemberStatusEnum.NORMAL.getCode());
        //平台会员不需要配置渠道渠道信息
        relationDO.setChannel(null);

        //权限
        MemberRelationAuthDO relationAuth = new MemberRelationAuthDO();
        relationAuth.setAuth(memberAuth.getAuth());
        relationAuth.setRelation(relationDO);

        relationDO.setRelationAuth(relationAuth);

        //***************************
        //不需要执行审核流程，所以不用调用工作流服务
        //****************************
        relationDO.setValidateTask(new MemberValidateTaskDO("", "", MemberProcessTypeEnum.PLATFORM_VALIDATION.getCode()));
        relationRepository.saveAndFlush(relationDO);

        //创建“平台会员”的等级配置，新注册的会员默认为1级，如果等级配置已经存在，这里会查询返回
        //注意：这里要先在PaaS平台配置“平台”角色的等级、权益等
        MemberLevelConfigDO upperMemberLevelConfigDO = baseMemberLevelConfigService.findFirstLevel(relationDO);
        MemberLevelRightDO levelDO = new MemberLevelRightDO();
        levelDO.setMemberId(adminMember.getId());
        levelDO.setRoleId(adminRole.getId());
        levelDO.setSubMemberId(memberDO.getId());
        levelDO.setSubRoleId(roleDO.getId());
        //如果没有在PaaS平台配置等级，那么注册会员的等级为0
        levelDO.setLevel(upperMemberLevelConfigDO == null ? 0 : upperMemberLevelConfigDO.getLevel());
        levelDO.setLevelTag(upperMemberLevelConfigDO == null ? "" : upperMemberLevelConfigDO.getLevelTag());
        levelDO.setLevelConfig(upperMemberLevelConfigDO);
        levelDO.setScore(0);
        levelDO.setCurrentPoint(0);
        levelDO.setSumPoint(0);
        levelDO.setSumReturnMoney(new BigDecimal(0));
        levelDO.setSumUsedPoint(0);
        levelDO.setRelation(relationDO);

        //设置信用信息
        MemberCreditDO creditDO = new MemberCreditDO();
        creditDO.setMemberId(adminMember.getId());
        creditDO.setRoleId(adminRole.getId());
        creditDO.setSubMemberId(memberDO.getId());
        creditDO.setSubRoleId(roleDO.getId());
        creditDO.setAfterSaleCommentPoint(0);
        creditDO.setComplainPoint(0);
        creditDO.setCreditPoint(0);
        creditDO.setComplainPoint(0);
        creditDO.setRegisterYearsPoint(0);
        creditDO.setTradeCommentPoint(0);
        creditDO.setRelation(relationDO);
        creditDO.setRegisterPointUpdateTime(LocalDateTime.now());
        creditDO.setTradeCommentStars(0);
        creditDO.setTradeCommentCount(0);
        creditDO.setAvgTradeCommentStar(ServiceConfig.DEFAULT_TRADE_COMMENT_STAR);

        //关联到会员关系
        relationDO.setLevelRight(levelDO);
        relationDO.setCredit(creditDO);
        relationRepository.saveAndFlush(relationDO);

        //***************************
        //创建会员的“超级管理员”角色 与 超级管理员用户
        //****************************
        MemberRoleDO memberRoleDO = new MemberRoleDO();
        memberRoleDO.setRoleName(MemberUserAuthTypeEnum.ADMIN.getMessage());
        memberRoleDO.setTypeEnum(MemberUserAuthTypeEnum.ADMIN.getCode());
        //默认具有IM即时通信权限
        memberRoleDO.setHasImAuth(EnableDisableStatus.ENABLE.getCode());
        //会员超级管理员角色不需要设置数据权限
        memberRoleDO.setAuthConfig(new HashSet<>());
        //菜单权限设置
        memberRoleDO.setAuth(roleDO.getRoleAuth().getAuth());
        memberRoleDO.setRemark(MemberStringEnum.MEMBER_ADMIN_ROLE_DEFAULT_REMARK.getName());
        memberRoleDO.setStatus(EnableDisableStatus.ENABLE.getCode());
        memberRoleDO.setMember(memberDO);
        memberRoleRepository.saveAndFlush(memberRoleDO);

        Set<MemberRoleDO> memberRoleSet = new HashSet<>();
        memberRoleSet.add(memberRoleDO);
        memberDO.setMemberRoles(memberRoleSet);

        //Step 2: 创建 超级管理员用户
        MemberUserDO userDO = new MemberUserDO();
        userDO.setCreateTime(LocalDateTime.now());
        userDO.setAccount(memberDO.getAccount());
        userDO.setPhone(memberDO.getPhone());
        userDO.setPassword(memberDO.getPassword());
        userDO.setCountryCode(memberDO.getCountryCode());
        userDO.setName(memberDO.getName());
        userDO.setEmail(memberDO.getEmail());
        userDO.setIdCardNo("");
        userDO.setJobTitle(MemberStringEnum.PLATFORM_SUPER_ADMIN_JOB_TITLE.getName());
        userDO.setLogo("");
        userDO.setStatus(EnableDisableStatus.ENABLE.getCode());
        userDO.setRelType(MemberRelationTypeEnum.OTHER.getCode());
        userDO.setTypeEnum(MemberUserAuthTypeEnum.ADMIN.getCode());
        userDO.setIsSales(EnableDisableStatus.DISABLE.getCode());
        userDO.setMember(memberDO);
        userDO.setRoles(memberRoleSet);
        //超级管理员用户不需要设置数据权限、渠道权限
        MemberUserAuthDO userAuth = new MemberUserAuthDO();
        userAuth.setAuth(memberAuth.getAuth());
        userAuth.setUser(userDO);
        userAuth.setDataAuth(new ArrayList<>());
        userAuth.setChannelAuth(new ArrayList<>());
        userAuth.setChannels(new HashSet<>());
        userDO.setUserAuth(userAuth);

        memberUserRepository.saveAndFlush(userDO);

        Set<MemberUserDO> memberUserSet = new HashSet<>();
        memberUserSet.add(userDO);
        memberDO.setUsers(memberUserSet);
        memberRepository.saveAndFlush(memberDO);

        //第六步骤：“注册”的审核记录（如果有审核流程，建议还是加上这个）
        baseMemberHistoryService.saveMemberOuterHistory(relationDO, adminRole.getRoleName(), MemberValidateHistoryOperationEnum.REGISTER, MemberOuterStatusEnum.getCodeMsg(relationDO.getOuterStatus()), "");

        //如果审核通过，通知支付服务创建资金账户
        payFeignService.notifyMemberAssetAccount(relationDO);

        //标品注册流程中，要异步通知报表服务、实时消息服务，这里不需要了
        return Wrapper.success();
    }

    /**
     * 生成会员注册资料
     * @param detailMap 要新增的注册资料Map对象，Key为 MemberConfigDO的fieldName，value为注册资料的值
     * @param roleDO 会员角色
     * @return 会员注册资料
     */
    private Wrapper<List<MemberRegisterDetailDO>> checkMemberRegisterDetail(Map<String, Object> detailMap, RoleDO roleDO) {
        //因为注册资料是关联到角色的，会员注册不同角色时，所要填写的注册资料是不一样的，所以要根据角色查询注册资料
        List<MemberConfigDO> memberConfigList = new ArrayList<>(roleDO.getConfigs());

        if(CollectionUtils.isEmpty(detailMap)) {
            return Wrapper.success(new ArrayList<>());
        }

        List<MemberRegisterDetailDO> registerDetailList = new ArrayList<>();
        for (Map.Entry<String, Object> entry : detailMap.entrySet()) {
            String key = entry.getKey();
            String value = entry.getValue() instanceof HashMap ? SecurityStringUtils.serializeObject(entry.getValue()) : String.valueOf(entry.getValue());

            MemberConfigDO configDO = memberConfigList.stream().filter(c -> c.getFieldName().equals(key)).findFirst().orElse(null);
            if (configDO == null) {
                return Wrapper.fail(ResponseCode.MC_MS_MEMBER_DETAIL_FIELD_DOES_NOT_EXIST);
            }

            Wrapper<DetailCheckBO> checkResult = baseMemberRegisterDetailService.checkDetail(configDO, value);
            if(checkResult.getCode() != ResponseCode.SUCCESS.getCode()) {
                return Wrapper.fail(checkResult.getCode(), checkResult.getMessage());
            }

            //这里其实是会员名称（会员名称是通过注册资料配置时，通过枚举字段定义的
            if(checkResult.getData().getTagEnum().equals(MemberConfigTagEnum.Member_Name.getCode())) {
                String memberName = checkResult.getData().getMemberName();
            }

            MemberRegisterDetailDO memberRegisterDetailDO = new MemberRegisterDetailDO();
            memberRegisterDetailDO.setMemberConfig(configDO);
            memberRegisterDetailDO.setGroupName(configDO.getGroupName());
            //版本
            memberRegisterDetailDO.setVersion(MemberDetailVersionEnum.TO_BE_VALIDATE.getCode());
            memberRegisterDetailDO.setFieldName(configDO.getFieldName());
            memberRegisterDetailDO.setFieldLocalName(configDO.getFieldLocalName());
            memberRegisterDetailDO.setFieldType(configDO.getFieldType());
            memberRegisterDetailDO.setAttr(configDO.getAttr());
            memberRegisterDetailDO.setTagEnum(configDO.getTagEnum());
            memberRegisterDetailDO.setStatus(configDO.getFieldStatus());
            memberRegisterDetailDO.setValidate(configDO.getValidate());
            memberRegisterDetailDO.setDetail(checkResult.getData().getDetail());
            memberRegisterDetailDO.setProvinceCode(checkResult.getData().getProvinceCode());
            memberRegisterDetailDO.setProvinceName(checkResult.getData().getProvinceName());
            memberRegisterDetailDO.setCityCode(checkResult.getData().getCityCode());
            memberRegisterDetailDO.setCityName(checkResult.getData().getCityName());
            memberRegisterDetailDO.setDistrictCode(checkResult.getData().getDistrictCode());
            memberRegisterDetailDO.setDistrictName(checkResult.getData().getDistrictName());
            memberRegisterDetailDO.setLabels(checkResult.getData().getLabels());
            registerDetailList.add(memberRegisterDetailDO);
        }

        return Wrapper.success(registerDetailList);
    }
}
